using Gateway.Common.Enums;
using Gateway.IQuery.Menu;
using Gateway.IQuery.Menu.Result;
using Gateway.IRepositories;

namespace Gateway.Query;

/// <summary>
/// 菜单查询服务
/// </summary>
public class MenuQuery : IMenuQuery
{
    private readonly IQueryRepository _repository;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="repository"></param>
    public MenuQuery(IQueryRepository repository)
    {
        _repository = repository;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<MenuDetailResult> GetDetail(string id)
    {
        var data = await _repository.QueryFirstOrDefaultAsync<MenuDetailResult>(
            @"select   menuid, name, path, title, icon, type, component, tag, hidden, affix, createdby, creatorname, createdtime, lastmodifiedby, lastmodifiername, lastmodifiedtime, disabled, parentid,levelCode from  Menu where Deleted='N' and menuId=@id",
            new { id });
        if (data != null)
        {
            var apis = await _repository.QueryListAsync<MenuApiAuthResult>(
                @"select * from MenuApiAuth where MenuId=@id", new { id });
            data.Apis = apis;
        }

        return data;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public async Task<List<MenuTreeResult>> GetTree()
    {
        var allMenus = await GetAllMenu();
        return await GetTreeResult(allMenus);
    }

    private async Task<List<MenuTreeResult>> GetTreeResult(List<MenuDetailResult> menus)
    {
        var menuIds = menus.Select(p => p.MenuId).ToList();

        var apis = await GetApisByMenuIds(menuIds);

        var rootList = menus.Where(p => string.IsNullOrWhiteSpace(p.ParentId)).OrderBy(p => p.LevelCode).ToList();
        List<MenuTreeResult> result = new List<MenuTreeResult>();
        foreach (var item in rootList)
        {
            var data = GetAggregateRoot(item, menus,apis);
            result.AddRange(data);
        }

        return result;
    }

    private async Task<List<MenuApiAuthResult>> GetApisByMenuIds(List<string> menuIds)
    {
        if (menuIds?.Count <= 0)
            return new List<MenuApiAuthResult>();
        var apis = await _repository.QueryListAsync<MenuApiAuthResult>(
            $@"select * from MenuApiAuth where MenuId in ({string.Join(",", menuIds.Select(p => $"'{p}'"))})");
        return apis;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="roleIds"></param>
    /// <returns></returns>
    public async Task<List<MenuTreeResult>> GetAuthTreeByRoleIds(List<string> roleIds)
    {
        var menus = await _repository.QueryListAsync<MenuDetailResult>($@"
select 
   distinct  m.menuid,m.name,m.path,m.title,m.icon,m.type,m.component,m.tag,m.hidden,m.affix,m.createdby,m.creatorname,m.createdtime,m.lastmodifiedby,m.lastmodifiername,m.lastmodifiedtime,m.disabled,m.parentid,m.seqno,m.active,m.color,m.fullpage,m.hiddenbreadcrumb,m.redirect,m.levelCode
    
    from  Menu m
join RoleMenu rm on m.MenuId = rm.MenuId
where m.Deleted='N' and m.Disabled='N'
and rm.RoleId in ({(string.Join(",", roleIds.Select(p => $"'{p}'")))})
");
        return await GetTreeResult(menus);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="roleIds"></param>
    /// <returns></returns>
    public async Task<List<string>> GetFuncPermissionByRoleIds(List<string> roleIds)
    {
        var permissions = await _repository.QueryListAsync<string>($@"
select 
   distinct  m.name
    from  Menu m
join RoleMenu rm on m.MenuId = rm.MenuId
where m.Deleted='N' and m.Disabled='N' and m.Type='button'
and rm.RoleId in ({(string.Join(",", roleIds.Select(p => $"'{p}'")))})
");
        return permissions;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="roleIds"></param>
    /// <returns></returns>
    public async Task<List<MenuApiAuthResult>> GetMenuApis(List<string> roleIds)
    {
        var apis = await _repository.QueryListAsync<MenuApiAuthResult>($@"
select 
  distinct MAA.Code,MAA.MenuId,MAA.Url
    from  Menu m
join RoleMenu rm on m.MenuId = rm.MenuId
join MenuApiAuth MAA on m.MenuId = MAA.MenuId
where m.Deleted='N' and m.Disabled='N'
and rm.RoleId in ({(string.Join(",", roleIds.Select(p => $"'{p}'")))})
");
        return apis;
    }

    /// <summary>
    /// 递归组织结构
    /// </summary>
    /// <param name="root"></param>
    /// <param name="list"></param>
    /// <param name="apis"></param>
    /// <returns></returns>
    private List<MenuTreeResult> GetAggregateRoot(MenuDetailResult root, List<MenuDetailResult> list,List<MenuApiAuthResult> apis)
    {
        List<MenuTreeResult> result = new List<MenuTreeResult>();
        var rootModel = new MenuTreeResult()
        {
            Name = root.Name,
            Path = root.Path,
            Component = root.Component,
            MenuId = root.MenuId,
            SeqNo = root.SeqNo,
            Meta = new MenuTreeMetaResult()
            {
                Affix = (root.Affix ?? BooleanStatusEnum.No.Value) == BooleanStatusEnum.Yes.Value,
                Hidden = (root.Hidden ?? BooleanStatusEnum.No.Value) == BooleanStatusEnum.Yes.Value,
                Icon = root.Icon,
                Tag = root.Tag,
                Title = root.Title,
                Type = root.Type,
                HiddenBreadcrumb = (root.HiddenBreadcrumb ?? BooleanStatusEnum.No.Value) == BooleanStatusEnum.Yes.Value,
                Fullpage = (root.FullPage ?? BooleanStatusEnum.No.Value) == BooleanStatusEnum.Yes.Value,
                Color = root.Color,
                Active = root.Active,
                Redirect = root.Redirect
            },
            ParentId = root.ParentId
        };
        rootModel.Children = new List<MenuTreeResult>();
        rootModel.Apis = apis.Where(p => p.MenuId.Equals(rootModel.MenuId)).ToList();
        string id = root.MenuId;
        if (!string.IsNullOrWhiteSpace(id))
        {
            var child = list.Where(p => (p.ParentId ?? "").Equals(id)).OrderBy(p => p.LevelCode).ToList();
            if (child.Count > 0)
            {
                foreach (var item in child)
                {
                    var tmpList = GetAggregateRoot(item, list,apis);
                    rootModel.Children.AddRange(tmpList);
                }
                // result.Add(rootModel);
            }
        }

        result.Add(rootModel);
        return result.OrderBy(p => p.SeqNo).ToList();
    }

    /// <summary>
    /// 获取所有菜单
    /// </summary>
    /// <returns></returns>
    public async Task<List<MenuDetailResult>> GetAllMenu()
    {
        var data = await _repository.QueryAsync<MenuDetailResult>(
            "select  menuid, name, path, title, icon, type, component, tag, hidden, affix, createdby, creatorname, createdtime, lastmodifiedby, lastmodifiername, lastmodifiedtime, disabled, parentid, seqno, active, color, fullpage, hiddenbreadcrumb, redirect,levelCode from  Menu where Deleted='N'");
        return data.ToList();
    }
}